<?php
/*
 *	Jphpquery-1.0.0.php
 *	name:xiaojia
 *	email:iatt@qq.com
 *	qq:273142650
 *	time:2011.12.26 13:57
*/
	
	interface jPhpQueryInterface
	{
		public function find($selector);
		public function html($markup);
	}

	class jPhpQuery implements jPhpQueryInterface
	{
		
		public $htmldom          = NULL;
		
		public $selectordom      = array();
		
		public $selectordomTemp  = array();
		
		public $selector         = array();
		
		public $selectorTemp     = array();
		
		public $body             = array();
		
		protected $regexp        = array(
			'htmldom'            => '/<\w+[^>]*>[\S\s]*?(?=<)|<\/\w+[^>]*>[\S\s]*?(?=<)|<\/[^>]*>|<\!DOCTYPE[^>]*>/',
			
			'bodystart'          => '/<body[^>]*>/i',
			
			'bodyend'            => '/<\/body>/i',
			
			'tag'                => '/<(\/|)\w+/i',
			
			'tagstart'           => '/<\w+[^>]*>/i',
			
			'grandfather'        => '/.+\s.+/i',
			
			'parent'             => '/.+>.+/i',
			
			'attr'               => '/(^\#|^\.|^\:\[)/i',
			
			'attrValue'          => '/\:\[|\]/ig',
			
			'attrElem'           => '/.*?(?=\.|\#|\:)|.*/i',
			
			'getAttr'            => '/\w+|[\.\#\:](\w+|\[(\w+|\w+\=.*?)\])/i',
			
			'elements'           => '(first|last|even|odd|eq|gt|lt|not|header|contains|empty|input|text|password|radio|checkbox|submit|reset|button|image|file|enabled|disabled|checked|selected|\[)',
			
			'attrValue'          => '/^\:|\(.*\)|\[|\]/i',
			
			'id'                 => '/^\#/i',
			
			'class'              => '/^\./i',
		);
		
		protected $alonetag      = array('input', 'img', 'br', 'hr', 'meat', 'param', 'embed');
		
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
		 
		public function __construct($dom)
		{
			
			$opendom = @fopen($dom, 'r');
			
			if ($opendom) {
				
				$htmldom = '';
				
				while ($html = fread($opendom, 8192)) {
					$htmldom .= $html;
				}
				
				$this -> htmldom = $htmldom;
				
			}  else {
				
				$this -> htmldom = $dom;
				
			}
			
			$this -> init();
			
			return $this;
			
		}
		
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
		 
		public function document ($document)
		{
			
			if (is_array($document)) {
				
				$this -> selectordom[] = $document;
				
			} else {
				
				$this -> selector[] = $this -> findSelector($document);
				$this -> selectordom[] = $this -> body;
				$this -> traverse();
				
			}
			
			return $this;
			
		}
		
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
		 
		public function find ($selector, $end = 0)
		{
			
			$this -> selector[] = $this -> findSelector($selector);
			
			$this -> traverse();
			
			if ($end === 1) {
			
				$selectordom = $this -> selectordom;
				
				$this -> selectordom = array();
				
				return end($selectordom);
			
			} elseif ($end === 0) {
			
				return $this;
			
			}
			
		}
		
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
		
		public function obj ()
		{
			
			$selectordom = $this -> selectordom;
			
			$this -> selectordom = array();
				
			return end($selectordom);
		
		}
			
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
		 
		public function html ($markup = NULL)
		{
			
		}
					
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
			
		protected function traverse ()
		{
			
			foreach ($this -> selector as $key => $val) {
				
				$selectordom = end($this -> selectordom);
			
				$index = count($this -> selectordom);
				
				$this -> getTempDom($val, $selectordom, $index);
				
				$this -> selector_write($index);
				
				//unset($this -> selector[$key]);
				
			}
			
		}

		protected function getTempDom ($selector, $selectordom, $index, $selectorIndex = 0)
		{
			
			foreach ($selector as $key => $val) {
				
				switch ($val['type']) {
					case 'tag':
						
						if (empty($val['value'])) {
						
							$this -> multipleAttr($val['attr'], $index);
							$this -> multipleAttr_tag($index);
						
						} else {
						
							$this -> htmleach('/<'.$val['value'].'(\s+|>)[^><]*/i', $selectordom, $index, $selectorIndex);
						
						}
					
					
					break;
					case 'attr':
					
						if (empty($val['elem'])) {
						
							$this -> multipleAttr($val['attr'], $index);
							$this -> multipleAttr_tag($index);
							
						} else {
					
							if (empty($val['value'])) {
								
								$this -> htmleach('/<\w+[^><]*?\s+'.$val['elem'].'(\s+|\=)[^><]*>/i', $selectordom, $index, $selectorIndex);
							
							} else {
								
								$this -> htmleach('/<\w+[^><]*?'.$val['elem'].'\s*=\s*"'.$val['value'].'"[^><]*>/i', $selectordom, $index, $selectorIndex);
							
							}
						}
						
					break;
					case 'grandfather':
					
						$this -> multipleAttr($val['elem'], $index);
						$this -> multipleAttr_grandfather($index);
					
					break;
				}
				
			}
			
		}

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
		
		protected function multipleAttr ($elem, $index)
		{
			
			foreach ($elem as $key => $val) {
				
				$this -> selectorTemp[] = $this -> findSelector($val);
				
			}
			
			$this -> selectordomTemp[] = end($this -> selectordom);
			
			foreach ($this -> selectorTemp as $key => $val) {
				
				$selectordomTemp = end($this -> selectordomTemp);

				$indexTemp = count($this -> selectordomTemp);
				
				$this -> getTempDom($val, $selectordomTemp, $indexTemp, $key);
				
				//unset($this -> selectorTemp[$key]);
				
			}
			
		}

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		protected function multipleAttr_grandfather ($index)
		{
								
			$selectordomTemp = end($this -> selectordomTemp);
			
			if (empty($selectordomTemp)) {
				
				$this -> selectordomTemp = array();
				$this -> selectordomTemp[$index] = array();
				
			} else {
				
				$this -> selectordomTemp[$index] = $this -> selectordomTemp[1];
				
			}
			
		}

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		protected function multipleAttr_tag ($index)
		{
			
			$this -> selectordomTemp[$index] = end($this -> selectordomTemp);
			
		}

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		protected function htmleach ($regexp, $selectordom, $index, $selectorIndex)
		{
			
			$endArray = array();
			
			$parent = 0;
			
			$selectorIndex > 1 && $selectorIndex = 1;
			
			foreach ($selectordom as $k => $v) {
				
				if ($parent >= $selectorIndex) {
				
					if (preg_match($regexp, $v) > 0) {
						
						$this -> selectordomTemp[$index][$k] = $v;
						
						$tagGet = $this -> tagGet($v);
						
						if (!in_array($tagGet, $this -> alonetag)) {
							
							$endArray[] = $tagGet;
							
						}
						
					
					} else {
					
						if (count($endArray) > 0) {
							
							if (preg_match($this -> regexp['tagstart'], $v) > 0) {
								
								$this -> selectordomTemp[$index][$k] = $v;
								
								$tagGet = $this -> tagGet($v);
								
								if (!in_array($tagGet, $this -> alonetag)) {
									$endArray[] = $tagGet;
								}
								
							}
							
							if (preg_match('/<\/('.implode('|', $endArray).')>/i', $v) > 0) {
								
								$this -> selectordomTemp[$index][$k] = $v;
								
								$endTag = array_search($this -> tagGet($v, 2), $endArray);
									
								unset($endArray[$endTag]);
								
							}
							
						}
						
					}
					
				}
				
				$parent++;
				
			}
			
			if (empty($this -> selectordomTemp[$index])) {
				
				$this -> selectordomTemp[$index] = array();
				
			}
			
		}

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		protected function selector_write ($index)
		{
			
			foreach ($this -> selectordomTemp[$index] as $key => $val) {
				
				$this -> selectordom[$index][$key] = $val;
				
			}
			
			@ksort($this -> selectordom[$index]);
			
			if (empty($this -> selectordom[$index])) {
				
				$this -> selectordom[$index] = array();
				
			}
						
			$this -> selectordomTemp = array();
			
		}

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		protected function getbody ()
		{
			
			$start = false;
			
			foreach ($this -> htmldom[0] as $k => $v) {
				
				if (preg_match($this -> regexp['bodystart'], $v) > 0) {
					$this -> body[$k] = $v;
					$start = true;
				}
				
				if ($start) {
					
					if (preg_match($this -> regexp['bodyend'], $v) > 0) {
						
						$this -> body[$k] = $v;
						
						$start = false;
						
					} else {
						
						$this -> body[$k] = $v;
						
					}
					
				}
				
			}
			
			if (count($this -> body) === 0) {
				
				$this -> body = $this -> htmldom[0];
				
			}
			
		}	

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		protected function tagGet ($tag, $t = 1)
		{
			preg_match($this -> regexp['tag'], $tag, $tagArray);
					
			return substr($tagArray[0], $t);
		}

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		protected function findSelector ($selector)
		{
			
			$sequence = explode(',', $selector);
			
			$selectorCount = count($this -> selector);
			
			foreach ($sequence as $key => $val) {
				
				if ($this -> selectorType('grandfather', $val)) {
					
					$selectorTemp[] = $this -> selectorArrayAdd('grandfather', $val);
					
				} elseif ($this -> selectorType('parent', $val)) {
					
					$selectorTemp[] = $this -> selectorArrayAdd('parent', $val);
					
				} elseif ($this -> selectorType('attr', $val)) {
					
					$selectorTemp[] = $this -> selectorArrayAdd('attr', $val);
					
				} else {
					
					$selectorTemp[] = $this -> selectorArrayAdd('tag', $val);
					
				}
				
			}
			
			return $selectorTemp;
			
		}
		
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 		protected function selectorRemoveType ($regexp, $selector)
		{
			return preg_replace($this -> regexp[$regexp], '', $selector);
		}
 		
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
		protected function selectorArrayAdd ($type, $selector)
		{
			
			$inputType = array('text', 'password', 'radio', 'checkbox', 'image', 'file', 'reset', 'submit', 'button');
			$buttonType = array('reset', 'submit', 'button');
			
			switch ($type) {
				case 'grandfather':
				
					$elem  = explode(' ', $selector);
					$value = '';
					$attr  = '';
				
				break;
				case 'attr':
				
					if ($this -> selectorType('id', $selector)) {
						
						$getAttr = $this -> getAttr($selector, 'id');
						
						$elem  = 'id';
						
						$value = $getAttr[0];
						
						$attr  = $getAttr[1];
						
					} elseif ($this -> selectorType('class', $selector)) {
						
						$getAttr = $this -> getAttr($selector, 'class');
						
						$elem  = 'class';
						
						$value = $getAttr[0];
						
						$attr  = $getAttr[1];
						
					} else {
						
						$selector = $this -> selectorRemoveType('attrValue', $selector);
						
						$selector = explode('=', $selector);
						
						$elem     = $selector[0];
						
						$value    = @preg_quote($selector[1], '/');
						
						$attr     = '';
						
					}
				
				break;
				case 'parent':
				
					$elem  = explode('>', $selector);
					
					$value = '';
					
				break;
				case 'tag':
						
					$getAttr = $this -> getAttr($selector);
					
					$elem  = '';
					
					$value = $getAttr[0];
					
					$attr  = $getAttr[1];
				
				break;
				case 'elements':
				
					/* else {
						
						$elem = $elemInArray = $this -> selectorRemoveType('attrValue', $selector);
						
						$value = '';
						
						if (in_array($elemInArray, $inputType)) {
							
							$elem = 'input:[type='.$elemInArray.']';
							
						}
						
						if (in_array($elemInArray, $buttonType)) {
							
							$elem .= ',button:[type='.$elemInArray.']';
							
						}
						
					}*/
				
				break;
			}
			
			return array(
				'type'  => $type,
				'elem'  => $elem,
				'value' => $value,
				'attr'  => $attr,
			);
		}

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		protected function getAttr ($selector, $regExt = NULL)
		{
			
			preg_match_all($this -> regexp['getAttr'], $selector, $getAttrAll);
			
			if (count($getAttrAll[0]) == 1) {
			
				if ($regExt !== NULL) {
					
					$selector = $this -> selectorRemoveType($regExt, $selector);
					
				}
			
				preg_match($this -> regexp['attrElem'], $selector, $value);
				
				$getAttr[0] = $value[0];
			
				$getAttr[1] = '';
				
			} else {
			
				$getAttr[0] = '';
			
				$getAttr[1] = $getAttrAll[0];
				
			}
			
			return $getAttr;
			
		}
		
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
		protected function selectorType ($regexp, $selector)
		{
			
			if (preg_match($this -> regexp[$regexp], $selector) > 0) {
				
				return true;
				
			} else {
			
				return false;
			
			}
			
		}
		
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
		 
		protected function init()
		{
			
			$dom = $this -> htmldom;
			
			preg_match_all($this -> regexp['htmldom'], $dom, $this-> htmldom);
			
			$this -> getbody();
			
		}
		
	}

?>